﻿using SDL2;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;

namespace BITUI.Audio
{
    //都将换成dotnet 兼容编码器实现
    //public class BackgroundMusic
    //{
    //    public IntPtr music;
    //    public void Free()
    //    {
    //        SDL_mixer.Mix_FreeMusic(music);
    //    }
    //}
    //public class AudioChunk
    //{
    //    public IntPtr chunk;
    //    public void Free()
    //    {
    //        SDL_mixer.Mix_FreeChunk(chunk);
    //    }
    //}
    public class AudioSystem
    {
        public bool AudioInited
        {
            get;
            private set;
        }


        internal AudioSystem()
        {
            var result = SDL.SDL_Init(SDL.SDL_INIT_TIMER | SDL.SDL_INIT_AUDIO);
            Console.WriteLine("init sdl audio=" + result);
            AudioInited = result == 0;
            if (AudioInited)
            {
                InitMixer();

            }
        }
        //這裏存一個，別讓GC回收了
        SDL.SDL_AudioSpec wanted_spec = new SDL.SDL_AudioSpec();
        System.Collections.Concurrent.ConcurrentDictionary<string, IMixer> mixers = new System.Collections.Concurrent.ConcurrentDictionary<string, IMixer>();
        BackGroundMixer mixer_BackGround = new BackGroundMixer();
        private void InitMixer()
        {
            wanted_spec.freq = 44100;
            wanted_spec.format = SDL.AUDIO_F32LSB;//根据系统决定合适的字节序
            wanted_spec.channels = 2;
            wanted_spec.silence = 0;
            wanted_spec.samples = 1024;
            wanted_spec.size = 1024;
            wanted_spec.callback = SDLMixAudio;
            var resultopen = SDL.SDL_OpenAudio(ref wanted_spec, IntPtr.Zero);
            if (resultopen < 0)
            {
                Console.WriteLine("OpenAudio Error.");
            }
            SDL.SDL_PauseAudio(0);

            this.AddMixer("_background", mixer_BackGround);
        }

        public unsafe static void MixFloatAudio(float* stream, int streampos, int streamlen, float[] srcbuf, int srcoffset, int srclen, byte vol = 128)
        {
            if (srclen + streampos > streamlen)
                throw new Exception("write error pos");
            if (vol > 128)
                throw new Exception("error volume");

            unsafe
            {

                IntPtr destptr = (IntPtr)(stream + streampos);
                fixed (float* srcdata = srcbuf)
                {
                    IntPtr srcptr = (IntPtr)(srcdata + srcoffset);
                    SDL.SDL_MixAudio(destptr, srcptr, (uint)(srclen * 4), vol);
                }
            }
        }
        private void SDLMixAudio(IntPtr userdata, IntPtr stream, int len)
        {
            int vol = 128;//0 到 128；
            var floatcount = len / 4;
            unsafe
            {
                //原始数据居然是不干净的，需要先清个零
                float* data = (float*)stream;
                for (var i = 0; i < floatcount; i++)
                {
                    data[i] = 0;
                }
                
                foreach (var m in mixers)
                {
                    m.Value.MixFloat_44100_2(data, floatcount);
                }

            }
        }
        /// <summary>
        /// mixer 混音器，一个Mixer可以混多个音源，也可以用来录音，混音器是低级接口
        /// 直接播放声音基于混音器实现
        /// </summary>
        public interface IMixer
        {
            unsafe void MixFloat_44100_2(float* stream, int streamlen);
            //bool GetAudioData(int floatcount, out IntPtr outdata, out int outfloatcount);
        }
        public bool AddMixer(string name, IMixer mixer)
        {
            return this.mixers.TryAdd(name, mixer);
        }
        public IMixer GetMixer(string name)
        {
            var b = this.mixers.TryGetValue(name, out IMixer v);
            if (b) return v;
            else return null;
        }
        public bool RemoveMixer(string name)
        {
            return this.mixers.TryRemove(name, out IMixer m);
        }
        ////背景音乐，背景音乐同时只能播放一个
        //public BackgroundMusic LoadBackgroundMusic(string filename)
        //{
        //    if (!AudioInited)
        //        throw new Exception("can not load music,because audio init error.");
        //    BackgroundMusic mus = new BackgroundMusic();
        //    mus.music = SDL_mixer.Mix_LoadMUS(filename);
        //    if (mus.music == IntPtr.Zero)
        //    {
        //        var errinfo = SDL.SDL_GetError();
        //        throw new Exception(errinfo);
        //    }
        //    return mus;
        //}
        public void PlayBackgroundMusic(string filename, bool bLoop = true, float fadeintime = 0)
        {
            mixer_BackGround.TryLoadAndPlay(filename, bLoop, fadeintime);
            //    if (fadeintime > 0)
            //    {
            //        SDL_mixer.Mix_FadeInMusic(music.music, bLoop ? -1 : 0, (int)(fadeintime * 1000));
            //    }
            //    else
            //    {
            //        SDL_mixer.Mix_PlayMusic(music.music, bLoop ? -1 : 0);
            //    }
        }
        //public void StopPlayBackgroundMusic(float fadeouttime = 0)
        //{
        //    if (fadeouttime > 0)
        //    {
        //        var pos = SDL_mixer.Mix_FadeOutMusic((int)(fadeouttime * 1000));
        //    }
        //    else
        //    {
        //        var pos = SDL_mixer.Mix_HaltMusic();
        //    }
        //}
        //public void PausePlaygroundMusic()
        //{
        //    SDL_mixer.Mix_PauseMusic();
        //}
        //public void ResumePlaygroundMusic()
        //{
        //    SDL_mixer.Mix_ResumeMusic();
        //}
        //public bool IsBackgroundMusicPlaying()
        //{
        //    return SDL_mixer.Mix_PlayingMusic() > 0;
        //}

        ////音效，可以同时播放N个
        //public AudioChunk LoadAudioChunk(string filename)
        //{
        //    IntPtr mus = SDL_mixer.Mix_LoadWAV(filename);
        //    if (mus == IntPtr.Zero)
        //    {
        //        var errinfo = SDL.SDL_GetError();
        //        throw new Exception(errinfo);
        //    }
        //    AudioChunk chunk = new AudioChunk();
        //    chunk.chunk = mus;
        //    return chunk;
        //}
        //public void PlayChunk(AudioChunk chunk)
        //{
        //    SDL_mixer.Mix_PlayChannel(-1, chunk.chunk, 0);
        //}

    }
}
